package jkstatus

import (
	"encoding/json"
	"jkgo/jk/jklog"
	"jkgo/jk/jksys"
	"findService/ss/servicebase"
	"time"

	// "github.com/buger/jsonparser"
	"jkgo/jk/jkprotocol"
	"net"
)

/**
 * This model receive message from server, then parse msg with protocol,
 * and save data to struct, give response if necessary
 */

type Process struct {
	proto *jkprotocol.JKProtoV6
	conn  net.Conn
	data  string
	SS    *ServiceStatus
}

func ParseData(data string, conn net.Conn) (*Process, error) {
	p := &Process{}
	p.data = data
	p.conn = conn

	return p, nil
}

func (p *Process) transferData(mc *servicebase.MsgContent) error {
	findsrc := false
	finddst := false
	var conn net.Conn
	for k, v := range p.SS.remoteInstance {
		jklog.L().Debugln("range id of ", v.Info.ID)
		if v.Info.ID == mc.Src {
			findsrc = true
			continue
		}
		if v.Info.ID == mc.Dst {
			finddst = true
			conn = k
			continue
		}
		if findsrc && finddst {
			break
		}
	}

	if findsrc && finddst {
		jklog.L().Infof("find and send out to [%s] conn [%p]\n", finddst, conn)
		// Create list save transfer info, don't parse, just transfer with command
		//s, err := p.proto.JKProtoV6MakeTR(mc.Dst, p.proto.H.R, mc)
		p.proto.H.Transaction = time.Now().UnixNano()/1000000
		item := &MsgQueueItem{
			Proto: *p.proto,
			Conn: p.conn,
		}
		p.SS.msgQueue.Add(item)
		s, _ := p.proto.JKProtoV6MakeTR(service_selfname, p.proto.H.R, mc)
		conn.Write([]byte(s))
	} else {
		jklog.L().Errorln("not find src or dst, ignore")
		s, err := p.proto.JKProtoV6MakeCommonResponse("")
		if err != nil {
			jklog.L().Errorln("make resonse fail ", err)
		} else {
			p.conn.Write([]byte(s))
		}
	}
	return nil
}

func (p *Process) HandleMsg() bool {
	jklog.L().Debugln("handle message of ", p.data)
	pp, err := jkprotocol.JKProtoV6Parse(p.data)
	if err != nil {
		jklog.L().Errorf("Parser fail %s\n %s\n", err, p.data)
		return false
	}
	p.proto = pp
	p.SS.remoteInstance[p.conn].Info.ID = p.proto.H.ID
	jklog.L().Debugf("status process receive message: %v\n", *p.proto)

	switch p.proto.H.C {
	case jkprotocol.JKP_V6_KEEPALIVE_NAME:
		if p.proto.H.R {
			str, err := p.proto.JKProtoV6MakeKeepaliveResponse()
			if err != nil {
				jklog.L().Errorln("Generate Keepalive string err ", err)
				return false
			}
			jklog.L().Debugln("Give Response of keepalive msg ", str)
			p.SS.remoteInstance[p.conn].UpdateTime()
			p.SS.remoteInstance[p.conn].Info.ID = p.proto.H.ID
			p.conn.Write([]byte(str))
		}
	case jkprotocol.JKP_V6_REGISTER_NAME:
		jklog.L().Debugln("register command")
		// If use interface, can't transfer back to correct interface
		// so we define a new with body of the struct
		// Why can't transfer from interface ???
		type OutSys struct {
			H jkprotocol.JKProtoV6Header
			B jksys.KFSystemInfo
		}
		var outSys OutSys
		err := json.Unmarshal([]byte(p.data), &outSys)
		if err != nil {
			jklog.L().Errorln("json unmarshal fail ", err)
			break
		}
		p.SS.remoteInstance[p.conn].SysInfo = outSys.B
		if p.proto.H.R {
			str, _ := pp.JKProtoV6MakeCommonResponse("")
			p.conn.Write([]byte(str))
		}
	case jkprotocol.JKP_V6_TR_NAME:
		mctmp := p.proto.B.(map[string]interface{})
		mc := &servicebase.MsgContent{
			Src: mctmp["Src"].(string),
			Dst: mctmp["Dst"].(string),
		}
		jklog.L().Infof("msg from [%s] send to [%s]\n", mctmp["Src"], mctmp["Dst"])
		item := p.SS.msgQueue.Find(pp.H.Transaction)
		if item != nil {
			jklog.L().Infoln("find response, transfer to dst")
			// Find exist, means response
			s, _ := pp.JKProtoV6MakeTR(service_selfname, false, mc)
			item.Conn.Write([]byte(s))
		} else {
			jklog.L().Infoln("find nothing, transfer between programs")
			// never find, give transfer
			p.transferData(mc)
		}
	}
	return true
}
